﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Sharp.DataTransferObject.CMS;
using Sharp.Domain.CMSBoundedContext.AritcleModule.Aggregates;
using Sharp.Domain.CMSBoundedContext.AritcleModule.GatherEngine;
using Sharp.Domain.CMSBoundedContext.VIUModule.Aggregates;
using Sharp.Domain.CMSBoundedContext.VIUModule.Services;
using Sharp.Domain.Repositories;
using Sharp.Infrastructure;
using Sharp.Infrastructure.Interfaces;
using Sharp.Infrastructure.Search;
using Sharp.ServiceContracts.CMS;
using ContactContext = Sharp.Infrastructure.ContactContext;
using Result = Sharp.Infrastructure.Result;

namespace Sharp.Application.CMS
{

    /// <summary>
    /// 内容管理服务
    /// </summary>
    public partial class CMSServiceImpl : ApplicationService, ICMSService
    {
        #region 私有字段

        private readonly IVIUService _viuService;
        private readonly IGatherEngineMain _gatherEngineMain;
        private readonly IGatherContentPage _gatherContentPage;


        private readonly IVIURepository _viuRepository;
        private readonly IVIUCategoryRepository _categoryRepository;
        private readonly IFieldRepository _fieldRepository;
        private readonly ITagRepository _tagRepository;
        private readonly IArticleRepository _articleRepository;
        private readonly ISpecialRepository _specialRepository;
        private readonly IColumnRepository _columnRepository;
        private readonly IGatherRepository _gatherRepository;

        #endregion

        #region 构造函数

        /// <summary>
        ///     初始化一个新的<c>CMSServiceImpl</c>实例。
        /// </summary>
        /// <param name="context"></param>
        /// <param name="viuRepository"></param>
        /// <param name="categoryRepository"></param>
        /// <param name="fieldRepository"></param>
        /// <param name="propertyRepository"></param>
        /// <param name="tagRepository"></param>
        /// <param name="articleRepository"></param>
        /// <param name="specialRepository"></param>
        /// <param name="columnRepository"></param>
        /// <param name="gatherRepository"></param>
        /// <param name="viuService"></param>
        /// <param name="gatherEngineMain"></param>
        /// <param name="gatherContentPage"></param>
        public CMSServiceImpl(IRepositoryContext context,
            IVIURepository viuRepository,
            IVIUCategoryRepository categoryRepository,
            IFieldRepository fieldRepository,
            ITagRepository tagRepository,
            IArticleRepository articleRepository,
            ISpecialRepository specialRepository,
            IColumnRepository columnRepository,
            IGatherRepository gatherRepository,

            IVIUService viuService,
            IGatherEngineMain gatherEngineMain,
            IGatherContentPage gatherContentPage
            )
            : base(context)
        {
            _viuRepository = viuRepository;
            _categoryRepository = categoryRepository;
            _fieldRepository = fieldRepository;
            _tagRepository = tagRepository;
            _articleRepository = articleRepository;
            _specialRepository = specialRepository;
            _columnRepository = columnRepository;
            _gatherRepository = gatherRepository;

            _viuService = viuService;
            _gatherEngineMain = gatherEngineMain;
            _gatherContentPage = gatherContentPage;
        }

        #endregion

        #region VIU

        #region 保存VIU

        public Result SaveVIU(VIUDTO dtomodel)
        {
            Result res = new Result();
            if (dtomodel.Id.IsEmpty())
            {
                var info = dtomodel.To<VIU>();

                if (dtomodel.FieldIds != null)
                {
                    info.EditorId = ContactContext.Current.UserId;
                    var fields = _fieldRepository.GetList(x => dtomodel.FieldIds.Contains(x.Id));
                    foreach (var field in fields)
                    {
                        info.Fields.Add(field);
                    }
                }

                if (dtomodel.TagIds != null)
                {
                    var tags = _tagRepository.GetList(x => dtomodel.TagIds.Contains(x.Id));
                    foreach (var t in tags)
                    {
                        info.Tags.Add(t);
                    }
                }
                if (dtomodel.MultiMedias != null)
                {
                    foreach (var p in info.MultiMedias)
                    {
                        p.Type = p.Type;
                        p.ThumbUrl = p.PicUrl;
                        p.PicUrl = p.PicUrl;
                        p.IsDefault = p.IsDefault;

                    }
                    if (dtomodel.MultiMedias.Any(x => x.IsDefault))
                    {
                        info.ThumbUrl = dtomodel.MultiMedias.First(x => x.IsDefault).PicUrl;
                    }
                    else
                    {
                        info.ThumbUrl = dtomodel.MultiMedias.First().PicUrl;
                    }
                }
                _viuRepository.Add(info);
            }
            else
            {
                var model = _viuRepository.Get(dtomodel.Id);
                model.Title = dtomodel.Title;
                model.Content = dtomodel.Content;
                model.CategoryId = dtomodel.CategoryId;
                model.Stars = dtomodel.Stars;
                model.Hits = dtomodel.Hits;
                model.Author = dtomodel.Author;
                model.IsElite = dtomodel.IsElite;
                model.IsHeadline = dtomodel.IsHeadline;
                model.IsOnTop = dtomodel.IsOnTop;
                model.AllowComment = dtomodel.AllowComment;
                model.Nature = dtomodel.Nature;
                model.Interest = (VIU.VIUInterest)Convert.ToInt32(dtomodel.Interest);
                model.Importance = (VIU.VIUImportance)Convert.ToInt32(dtomodel.Importance);
                model.Style = (VIU.VIUStyle)Convert.ToInt32(dtomodel.Style);
                model.EventDay = model.EventDay;
                model.PublishDay = model.PublishDay;


                model.Fields.Clear();
                model.Tags.Clear();
                model.MultiMedias.Clear();

                if (dtomodel.FieldIds != null)
                {
                    var fields = _fieldRepository.GetList(x => dtomodel.FieldIds.Contains(x.Id));
                    foreach (var field in fields)
                    {
                        model.Fields.Add(field);
                    }
                }
                if (dtomodel.TagIds != null)
                {
                    var tags = _tagRepository.GetList(x => dtomodel.TagIds.Contains(x.Id));
                    foreach (var t in tags)
                    {
                        model.Tags.Add(t);
                    }
                }
                if (dtomodel.MultiMedias != null && dtomodel.MultiMedias.Any())
                {
                    foreach (var p in dtomodel.MultiMedias)
                    {
                        model.MultiMedias.Add(new MultiMedia()
                        {
                            Type = (MediaType)Enum.Parse(typeof(MediaType), p.Type),
                            ThumbUrl = p.PicUrl,
                            PicUrl = p.PicUrl,
                            IsDefault = p.IsDefault
                        });
                    }
                    if (dtomodel.MultiMedias.Any(x => x.IsDefault))
                    {
                        model.ThumbUrl = dtomodel.MultiMedias.First(x => x.IsDefault).PicUrl;
                    }
                    else
                    {
                        model.ThumbUrl = dtomodel.MultiMedias.First().PicUrl;
                    }
                }

                _viuRepository.Update(model);
            }


            Context.Commit();
            return res;
        }

        #endregion

        public Infrastructure.Result<VIUDTO> GetVIU(Guid id)
        {
            if (id.IsEmpty())
            {
                return new Infrastructure.Result<VIUDTO>();
            }
            var info = _viuRepository.Get(id, x => x.Category, x => x.Fields, x => x.Tags,
                x => x.MultiMedias, x => x.ApproveHistories);
            VIUDTO data = null;
            if (info != null)
            {
                data = info.To<VIUDTO>();
                data.FieldIds = info.Fields.Select(x => x.Id).ToArray();
                data.TagIds = info.Tags.Select(x => x.Id).ToArray();
                //data.EditorName = info.Editor.UserName;

                data.ApproveHistories.Clear();
                info.ApproveHistories.OrderByDescending(x => x.CheckInTime).ToList().ForEach(x =>
                {
                    var history = x.To<ApproveHistoryDTO>();
                    //history.ApproverName = x.Approver.UserName;
                    data.ApproveHistories.Add(history);
                });
            }

            return new Infrastructure.Result<VIUDTO>()
            {
                Data = data
            };
        }

        /// <summary>
        ///     获取分页数据
        /// </summary> 
        /// <returns></returns>
        public Infrastructure.PagedResult<VIUDTO> GetVIUPaged(PagingFeature pf)
        {
            var paged = _viuRepository.Pagging(pf, null, x => x.Category, x => x.Fields, x => x.Tags);

            return paged.To<VIU, VIUDTO>();
        }

        public Result DeleteVIUs(Guid ids)
        {
            var res = new Result();
            if (ids == null)
            {
                res.Err = "参数不可为空。";
                return res;
            }

            _viuRepository.Remove(new List<Guid>() { ids }.ToArray());

            Context.Commit();

            return res;
        }

        #region Category

        public Result DeleteCategories(Guid[] ids)
        {
            var res = new Result();
            if (ids == null)
            {
                res.Err = "参数不可为空。";
                return res;
            }

            _categoryRepository.Remove(ids);

            Context.Commit();

            return res;
        }

        public Result SaveCategory(VIUCategoryDTO dtoModel)
        {
            Result res = new Result();
            if (dtoModel.Id.IsEmpty())
            {
                _categoryRepository.Add(dtoModel.To<VIUCategory>());
            }
            else
            {
                var persisted = _categoryRepository.Get(dtoModel.Id);
                persisted.Name = dtoModel.Name;
                persisted.ParentId = dtoModel.ParentId;
                persisted.Remark = dtoModel.Remark;

                _categoryRepository.Update(persisted);
            }
            _categoryRepository.Context.Commit();
            return res;
        }

        public Infrastructure.Result<VIUCategoryDTO> GetCategoryInfo(Guid id)
        {
            var res = new Infrastructure.Result<VIUCategoryDTO>();
            var data = _categoryRepository.Get(id);
            res.Data = data.To<VIUCategoryDTO>();
            return res;
        }

        public Infrastructure.Result<IEnumerable<VIUCategoryDTO>> GetCategoryList(bool treeData)
        {
            var res = new Infrastructure.Result<IEnumerable<VIUCategoryDTO>>();
            if (treeData)
            {
                var data = _categoryRepository.GetList(x => x.ParentId == null, "Id DESC", null,
                    x => x.Children, x => x.Tags);

                res.Data = data.To<VIUCategory, VIUCategoryDTO>();
            }
            else
            {
                res.Data = _categoryRepository.GetList().To<VIUCategory, VIUCategoryDTO>();
            }
            return res;
        }

        public Infrastructure.PagedResult<VIUCategoryDTO> GetCategoryPaged(PagingFeature pf)
        {
            var paged = _categoryRepository.Pagging(pf);

            return paged.To<VIUCategory, VIUCategoryDTO>();
        }

        #endregion


        #region Field

        public Result DeleteFields(Guid[] ids)
        {
            var res = new Result();
            if (ids == null)
            {
                res.Err = "参数不可为空。";
                return res;
            }

            _fieldRepository.Remove(ids);

            Context.Commit();

            return res;
        }

        public Result SaveField(FieldDTO dtoModel)
        {
            Result res = new Result();
            if (dtoModel.Id.IsEmpty())
            {
                _fieldRepository.Add(dtoModel.To<Field>());
            }
            else
            {
                var persisted = _fieldRepository.Get(dtoModel.Id);
                persisted.Name = dtoModel.Name;
                persisted.ParentId = dtoModel.ParentId;
                persisted.Remark = dtoModel.Remark;

                _fieldRepository.Update(persisted);
            }
            _fieldRepository.Context.Commit();
            return res;
        }

        public Infrastructure.Result<FieldDTO> GetFieldInfo(Guid id)
        {
            var res = new Infrastructure.Result<FieldDTO>();
            res.Data = _fieldRepository.Get(id).To<FieldDTO>();
            return res;
        }

        public Infrastructure.Result<IEnumerable<FieldDTO>> GetFieldList(bool treeData = true)
        {
            //暂时只考虑两层
            var list = _fieldRepository.GetList().To<Field, FieldDTO>();
            var res = new Infrastructure.Result<IEnumerable<FieldDTO>>();
            if (treeData)
            {
                var newList = new List<FieldDTO>();

                newList.AddRange(list.Where(x => x.ParentId == null));
                newList.ToList().ForEach(x =>
                {
                    if (x.Children == null)
                        x.Children = new List<FieldDTO>();
                    x.Children.AddRange(list.Where(y => y.ParentId == x.Id));
                });
                res.Data = newList;
            }
            else
            {
                res.Data = list;
            }
            return res;
        }

        #endregion


        #region Tag

        public Result DeleteTags(Guid[] ids)
        {
            var res = new Result();
            if (ids == null)
            {
                res.Err = "参数不可为空。";
                return res;
            }

            _tagRepository.Remove(ids);

            Context.Commit();

            return res;
        }


        /// <summary>
        /// 获取拼音首字母
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private string GetPinyinInitial(string name)
        {
            if (!Regex.IsMatch(name.Substring(0, 1), "[\u4e00-\u9fa5]")
                 && !Regex.IsMatch(name.Substring(0, 1), "\\d"))//不是中文&&不是数字
            {
                return name.Substring(0, 1);
            }
            string pingYin = Spell.Convert(name, true);//获取拼音
            return string.IsNullOrEmpty(pingYin) ? "*" : pingYin.Substring(0, 1);
        }

        public Result SaveTag(TagDTO dtoModel)
        {
            Result res = new Result();

            if (dtoModel.Id.IsEmpty())
            {
                dtoModel.Initial = GetPinyinInitial(dtoModel.Name);
                _tagRepository.Add(dtoModel.To<Tag>());
            }
            else
            {
                var persisted = _tagRepository.Get(dtoModel.Id);
                persisted.Name = dtoModel.Name;
                if (string.IsNullOrEmpty(dtoModel.Initial)==false)
                {
                    persisted.Initial = dtoModel.Initial;
                }

                persisted.Remark = dtoModel.Remark;
                persisted.CategoryId = dtoModel.CategoryId;
                persisted.IsHandled = true;//表示已经处理这个标签
                _tagRepository.Update(persisted);
            }
            _tagRepository.Context.Commit();
            return res;
        }

        public Infrastructure.Result<TagDTO> GetTagInfo(Guid id)
        {
            var data = _tagRepository.Get(id, x => x.Category);
            //临时措施
            if (data.Category != null)
                data.Category.Tags = null;
            var res = new Infrastructure.Result<TagDTO>();
            res.Data = data.To<TagDTO>();
            return res;
        }

        public Infrastructure.PagedResult<TagDTO> GetTagPaged(PagingFeature pf)
        {
            var paged = _tagRepository.Pagging(pf);//, null, x => x.Category

            var ouput = new Infrastructure.PagedResult<TagDTO>
            {
                PageSize = paged.PageSize,
                PageNumber = paged.PageNumber,
                TotalRecords = paged.TotalRecords,
                Data = paged.Data.Select(x => new TagDTO()
                {
                    Id = x.Id,
                    Name = x.Name,
                    CategoryId = x.CategoryId,
                    Remark = x.Remark
                }).ToList()
            };

            return ouput;
        }

        /// <summary>
        /// 批量导入标签
        /// </summary>
        /// <param name="dtoModel"></param>
        /// <returns></returns>
        public Result SaveBatchImportTag(TagBatchImportDTO dtoModel)
        {
            IList<Tag> tagList = new List<Tag>();
            dtoModel.TagList.ToList().ForEach(t =>
            {
                TagDTO dto = t;

                Tag tag = dto.To<Tag>();
                tag.Id = Guid.NewGuid();
                tag.Initial = GetPinyinInitial(tag.Name);

                tagList.Add(tag);
            });
            _tagRepository.BulkInsertAll("dbo.Tags", tagList);
            return new Result();
        }

        #endregion

        private void Build<T1, T3>(IEnumerable<T1> table, T3 node,
            Guid? parentValue)
            where T1 : ITreeEntity
            where T3 : ITreeEntity, new()
        {
            var rows = table.Where(x => x.ParentId == parentValue).OrderBy(x => x.OrderIndex);
            foreach (var row in rows)
            {
                var _node = new T3
                {
                    //Name = row.Title,
                    Id = row.Id,
                    ParentId = row.ParentId == null ? row.ParentId : null,
                };

                ((dynamic)node).Children.Add(_node);

                Build(table, _node, row.Id);
            }
        }

        /// <summary>
        /// 审核VIU
        /// </summary>
        /// <param name="viuId"></param>
        /// <param name="isChecked"></param>
        /// <param name="remark"></param>
        public Result CheckInVIU(Guid viuId, bool isChecked, string remark)
        {
            return _viuService.CheckInVIU(viuId, isChecked, remark);
        }
        public Result CheckInSpecial(ApproveHistory4SpecialDTO vm)
        {
            return _viuService.CheckInSpecial(vm.SpecialId, vm.IsChecked, vm.Remark);
        }
        #endregion

        #region Article

        public Result DeleteArticles(Guid[] ids)
        {
            var res = new Result();
            if (ids == null)
            {
                res.Err = "参数不可为空。";
                return res;
            }

            _articleRepository.Remove(ids);

            Context.Commit();

            return res;
        }

        public Result SaveArticle(ArticleDTO dtoModel)
        {
            Result res = new Result();
            if (dtoModel.Id.IsEmpty())
            {
                Article article = dtoModel.To<Article>();
                article.CheckInTime = DateTime.Now;
                _articleRepository.Add(article);
            }
            else
            {
                var persisted = _articleRepository.Get(dtoModel.Id);
                persisted.Title = dtoModel.Title;
                persisted.Content = dtoModel.Content;

                _articleRepository.Update(persisted);
            }
            _articleRepository.Context.Commit();
            return res;
        }

        public Infrastructure.Result<ArticleDTO> GetArticleInfo(Guid id)
        {
            var res = new Infrastructure.Result<ArticleDTO>();
            res.Data = _articleRepository.Get(id).To<ArticleDTO>();
            return res;
        }

        public Infrastructure.PagedResult<ArticleDTO> GetArticlePaged(PagingFeature pf)
        {
            var paged = _articleRepository.Pagging(pf, null, x => x.Gather).To<Article, ArticleDTO>();

            paged.Data.ForEach(x =>
            {
                x.GatherName = x.Gather != null ? x.Gather.Name : "";
                x.Gather = null;
                x.Content = "";
            });
            return paged;
        }

        #endregion
    }
}